home *** CD-ROM | disk | FTP | other *** search
/ Aminet 1 (Walnut Creek) / Aminet - June 1993 [Walnut Creek].iso / aminet / util / gnu / textutl3.lha / textutils-1.3 / src / csplit.c < prev    next >
C/C++ Source or Header  |  1992-06-29  |  30KB  |  1,309 lines

  1. /* csplit - split a file into sections determined by context lines
  2.    Copyright (C) 1991 Free Software Foundation, Inc.
  3.  
  4.    This program is free software; you can redistribute it and/or modify
  5.    it under the terms of the GNU General Public License as published by
  6.    the Free Software Foundation; either version 2, or (at your option)
  7.    any later version.
  8.  
  9.    This program is distributed in the hope that it will be useful,
  10.    but WITHOUT ANY WARRANTY; without even the implied warranty of
  11.    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12.    GNU General Public License for more details.
  13.  
  14.    You should have received a copy of the GNU General Public License
  15.    along with this program; if not, write to the Free Software
  16.    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
  17.  
  18. /* Written by Stuart Kemp, cpsrk@groper.jcu.edu.au.
  19.    Modified by David MacKenzie, djm@gnu.ai.mit.edu. */
  20.  
  21. #include <stdio.h>
  22. #include <getopt.h>
  23. #include <ctype.h>
  24. #include <sys/types.h>
  25. #include <signal.h>
  26. #include "regex.h"
  27. #include "system.h"
  28.  
  29. #if !defined(USG) && !defined(STDC_HEADERS)
  30. char *memchr ();
  31. #endif
  32.  
  33. #ifdef STDC_HEADERS
  34. #include <stdlib.h>
  35. #else
  36. char *malloc ();
  37. char *realloc ();
  38. #endif
  39.  
  40. void error ();
  41.  
  42. void cleanup ();
  43. void close_output_file ();
  44. void create_output_file ();
  45. void save_line_to_file ();
  46. void usage ();
  47.  
  48. #ifndef TRUE
  49. #define FALSE 0
  50. #define TRUE 1
  51. #endif
  52.  
  53. /* Increment size of area for control records. */
  54. #define ALLOC_SIZE 20
  55.  
  56. /* The default prefix for output file names. */
  57. #define DEFAULT_PREFIX    "xx"
  58.  
  59. typedef int boolean;
  60.  
  61. /* A compiled pattern arg. */
  62. struct control
  63. {
  64.   char *regexpr;        /* Non-compiled regular expression. */
  65.   struct re_pattern_buffer re_compiled;    /* Compiled regular expression. */
  66.   int offset;            /* Offset from regexp to split at. */
  67.   int lines_required;        /* Number of lines required. */
  68.   int repeat;            /* Repeat count. */
  69.   int argnum;            /* ARGV index. */
  70.   boolean ignore;        /* If true, produce no output (for regexp). */
  71. };
  72.  
  73. /* Initial size of data area in buffers. */
  74. #define START_SIZE    8191
  75.  
  76. /* Increment size for data area. */
  77. #define INCR_SIZE    2048
  78.  
  79. /* Number of lines kept in each node in line list. */
  80. #define CTRL_SIZE    80
  81.  
  82. #ifdef DEBUG
  83. /* Some small values to test the algorithms. */
  84. #define START_SIZE    200
  85. #define INCR_SIZE    10
  86. #define CTRL_SIZE    1
  87. #endif
  88.  
  89. /* A string with a length count. */
  90. struct cstring
  91. {
  92.   int len;
  93.   char *str;
  94. };
  95.  
  96. /* Pointers to the beginnings of lines in the buffer area.
  97.    These structures are linked together if needed. */
  98. struct line
  99. {
  100.   unsigned used;        /* Number of offsets used in this struct. */
  101.   unsigned insert_index;    /* Next offset to use when inserting line. */
  102.   unsigned retrieve_index;    /* Next index to use when retrieving line. */
  103.   struct cstring starts[CTRL_SIZE]; /* Lines in the data area. */
  104.   struct line *next;        /* Next in linked list. */
  105. };
  106.  
  107. /* The structure to hold the input lines.
  108.    Contains a pointer to the data area and a list containing
  109.    pointers to the individual lines. */
  110. struct buffer_record
  111. {
  112.   unsigned bytes_alloc;        /* Size of the buffer area. */
  113.   unsigned bytes_used;        /* Bytes used in the buffer area. */
  114.   unsigned start_line;        /* First line number in this buffer. */
  115.   unsigned first_available;    /* First line that can be retrieved. */
  116.   unsigned num_lines;        /* Number of complete lines in this buffer. */
  117.   char *buffer;            /* Data area. */
  118.   struct line *line_start;    /* Head of list of pointers to lines. */
  119.   struct line *curr_line;    /* The line start record currently in use. */
  120.   struct buffer_record *next;
  121. };
  122.  
  123. /* Input file descriptor. */
  124. int input_desc = 0;
  125.  
  126. /* List of available buffers. */
  127. struct buffer_record *free_list = NULL;
  128.  
  129. /* Start of buffer list. */
  130. struct buffer_record *head = NULL;
  131.  
  132. /* Partially read line. */
  133. char *hold_area = NULL;
  134.  
  135. /* Number of chars in `hold_area'. */
  136. unsigned hold_count = 0;
  137.  
  138. /* Number of the last line in the buffers. */
  139. unsigned last_line_number = 0;
  140.  
  141. /* Number of the line currently being examined. */
  142. unsigned current_line = 0;
  143.  
  144. /* Number of the last line in the input file. */
  145. unsigned last_line_in_file = 0;
  146.  
  147. /* If TRUE, we have read EOF. */
  148. boolean have_read_eof = FALSE;
  149.  
  150. /* Name of output files. */
  151. char *filename_space = NULL;
  152.  
  153. /* Prefix part of output file names. */
  154. char *prefix = NULL;
  155.  
  156. /* Number of digits to use in output file names. */
  157. int digits = 2;
  158.  
  159. /* Number of files created so far. */
  160. unsigned files_created = 0;
  161.  
  162. /* Number of bytes written to current file. */
  163. unsigned bytes_written;
  164.  
  165. /* Output file pointer. */
  166. FILE *output_stream = NULL;
  167.  
  168. /* Perhaps it would be cleaner to pass arg values instead of indexes. */
  169. char **global_argv;
  170.  
  171. /* If TRUE, do not print the count of bytes in each output file. */
  172. boolean suppress_count;
  173.  
  174. /* If TRUE, remove output files on error. */
  175. boolean remove_files;
  176.  
  177. /* The compiled pattern arguments, which determine how to split
  178.    the input file. */
  179. struct control *controls;
  180.  
  181. /* Number of elements in `controls'. */
  182. unsigned control_used;
  183.  
  184. /* The name this program was run with. */
  185. char *program_name;
  186.  
  187. /* Allocate N bytes of memory dynamically, with error checking.  */
  188.  
  189. char *
  190. xmalloc (n)
  191.      unsigned n;
  192. {
  193.   char *p;
  194.  
  195.   p = malloc (n);
  196.   if (p == NULL)
  197.     {
  198.       error (0, 0, "virtual memory exhausted");
  199.       cleanup ();
  200.     }
  201.   return p;
  202. }
  203.  
  204. /* Change the size of an allocated block of memory P to N bytes,
  205.    with error checking.
  206.    If P is NULL, run xmalloc.
  207.    If N is 0, run free and return NULL.  */
  208.  
  209. char *
  210. xrealloc (p, n)
  211.      char *p;
  212.      unsigned n;
  213. {
  214.   if (p == NULL)
  215.     return xmalloc (n);
  216.   if (n == 0)
  217.     {
  218.       free (p);
  219.       return 0;
  220.     }
  221.   p = realloc (p, n);
  222.   if (p == NULL)
  223.     {
  224.       error (0, 0, "virtual memory exhausted");
  225.       cleanup ();
  226.     }
  227.   return p;
  228. }
  229.  
  230. /* Keep track of NUM chars of a partial line in buffer START.
  231.    These chars will be retrieved later when another large buffer is read.
  232.    It is not necessary to create a new buffer for these chars; instead,
  233.    we keep a pointer to the existing buffer.  This buffer *is* on the
  234.    free list, and when the next buffer is obtained from this list
  235.    (even if it is this one), these chars will be placed at the
  236.    start of the new buffer. */
  237.  
  238. void
  239. save_to_hold_area (start, num)
  240.      char *start;
  241.      unsigned num;
  242. {
  243.   hold_area = start;
  244.   hold_count = num;
  245. }
  246.  
  247. /* Read up to MAX chars from the input stream into DEST.
  248.    Return the number of chars read. */
  249.  
  250. int
  251. read_input (dest, max)
  252.      char *dest;
  253.      unsigned max;
  254. {
  255.   int bytes_read;
  256.  
  257.   if (max == 0)
  258.     return 0;
  259.  
  260.   bytes_read = read (input_desc, dest, max);
  261.  
  262.   if (bytes_read == 0)
  263.     have_read_eof = TRUE;
  264.  
  265.   if (bytes_read < 0)
  266.     {
  267.       error (0, errno, "read error");
  268.       cleanup ();
  269.     }
  270.  
  271.   return bytes_read;
  272. }
  273.  
  274. /* Initialize existing line record P. */
  275.  
  276. void
  277. clear_line_control (p)
  278.      struct line *p;
  279. {
  280.   p->used = 0;
  281.   p->insert_index = 0;
  282.   p->retrieve_index = 0;
  283. }
  284.  
  285. /* Initialize all line records in B. */
  286.  
  287. void
  288. clear_all_line_control (b)
  289.      struct buffer_record *b;
  290. {
  291.   struct line *l;
  292.  
  293.   for (l = b->line_start; l; l = l->next)
  294.     clear_line_control (l);
  295. }
  296.  
  297. /* Return a new, initialized line record. */
  298.  
  299. struct line *
  300. new_line_control ()
  301. {
  302.   struct line *p;
  303.  
  304.   p = (struct line *) xmalloc (sizeof (struct line));
  305.  
  306.   p->next = NULL;
  307.   clear_line_control (p);
  308.  
  309.   return p;
  310. }
  311.  
  312. /* Record LINE_START, which is the address of the start of a line
  313.    of length LINE_LEN in the large buffer, in the lines buffer of B. */
  314.  
  315. void
  316. keep_new_line (b, line_start, line_len)
  317.      struct buffer_record *b;
  318.      char *line_start;
  319.      int line_len;
  320. {
  321.   struct line *l;
  322.  
  323.   /* If there is no existing area to keep line info, get some. */
  324.   if (b->line_start == NULL)
  325.     b->line_start = b->curr_line = new_line_control ();
  326.  
  327.   /* If existing area for lines is full, get more. */
  328.   if (b->curr_line->used == CTRL_SIZE)
  329.     {
  330.       b->curr_line->next = new_line_control ();
  331.       b->curr_line = b->curr_line->next;
  332.     }
  333.  
  334.   l = b->curr_line;
  335.  
  336.   /* Record the start of the line, and update counters. */
  337.   l->starts[l->insert_index].str = line_start;
  338.   l->starts[l->insert_index].len = line_len;
  339.   l->used++;
  340.   l->insert_index++;
  341. }
  342.  
  343. /* Scan the buffer in B for newline characters
  344.    and record the line start locations and lengths in B.
  345.    Return the number of lines found in this buffer.
  346.  
  347.    There may be an incomplete line at the end of the buffer;
  348.    a pointer is kept to this area, which will be used when
  349.    the next buffer is filled. */
  350.  
  351. unsigned
  352. record_line_starts (b)
  353.      struct buffer_record *b;
  354. {
  355.   char *line_start;        /* Start of current line. */
  356.   char *line_end;        /* End of each line found. */
  357.   unsigned bytes_left;        /* Length of incomplete last line. */
  358.   unsigned lines;        /* Number of lines found. */
  359.   unsigned line_length;        /* Length of each line found. */
  360.  
  361.   if (b->bytes_used == 0)
  362.     return 0;
  363.  
  364.   lines = 0;
  365.   line_start = b->buffer;
  366.   bytes_left = b->bytes_used;
  367.  
  368.   for (;;)
  369.     {
  370.       line_end = memchr (line_start, '\n', bytes_left);
  371.       if (line_end == NULL)
  372.     break;
  373.       line_length = line_end - line_start + 1;
  374.       keep_new_line (b, line_start, line_length);
  375.       bytes_left -= line_length;
  376.       line_start = line_end + 1;
  377.       lines++;
  378.     }
  379.  
  380.   /* Check for an incomplete last line. */
  381.   if (bytes_left)
  382.     {
  383.       if (have_read_eof)
  384.     {
  385.       keep_new_line (b, line_start, bytes_left);
  386.       lines++;
  387.       last_line_in_file = last_line_number + lines;
  388.     }
  389.       else
  390.     save_to_hold_area (line_start, bytes_left);
  391.     }
  392.  
  393.   b->num_lines = lines;
  394.   b->first_available = b->start_line = last_line_number + 1;
  395.   last_line_number += lines;
  396.  
  397.   return lines;
  398. }
  399.  
  400. /* Return a new buffer with room to store SIZE bytes, plus
  401.    an extra byte for safety. */
  402.  
  403. struct buffer_record *
  404. create_new_buffer (size)
  405.      unsigned size;
  406. {
  407.   struct buffer_record *new_buffer;
  408.  
  409.   new_buffer = (struct buffer_record *)
  410.     xmalloc (sizeof (struct buffer_record));
  411.  
  412.   new_buffer->buffer = (char *) xmalloc (size + 1);
  413.  
  414.   new_buffer->bytes_alloc = size;
  415.   new_buffer->line_start = new_buffer->curr_line = NULL;
  416.  
  417.   return new_buffer;
  418. }
  419.  
  420. /* Return a new buffer of at least MINSIZE bytes.  If a buffer of at
  421.    least that size is currently free, use it, otherwise create a new one. */
  422.  
  423. struct buffer_record *
  424. get_new_buffer (min_size)
  425.      unsigned min_size;
  426. {
  427.   struct buffer_record *p, *q;
  428.   struct buffer_record *new_buffer; /* Buffer to return. */
  429.   unsigned alloc_size;        /* Actual size that will be requested. */
  430.  
  431.   alloc_size = START_SIZE;
  432.   while (min_size > alloc_size)
  433.     alloc_size += INCR_SIZE;
  434.  
  435.   if (free_list == NULL)
  436.     new_buffer = create_new_buffer (alloc_size);
  437.   else
  438.     {
  439.       /* Use first-fit to find a buffer. */
  440.       p = new_buffer = NULL;
  441.       q = free_list;
  442.  
  443.       do
  444.     {
  445.       if (q->bytes_alloc >= min_size)
  446.         {
  447.           if (p == NULL)
  448.         free_list = q->next;
  449.           else
  450.         p->next = q->next;
  451.           break;
  452.         }
  453.       p = q;
  454.       q = q->next;
  455.     }
  456.       while (q);
  457.  
  458.       new_buffer = (q ? q : create_new_buffer (alloc_size));
  459.  
  460.       new_buffer->curr_line = new_buffer->line_start;
  461.       clear_all_line_control (new_buffer);
  462.     }
  463.  
  464.   new_buffer->num_lines = 0;
  465.   new_buffer->bytes_used = 0;
  466.   new_buffer->start_line = new_buffer->first_available = last_line_number + 1;
  467.   new_buffer->next = NULL;
  468.  
  469.   return new_buffer;
  470. }
  471.  
  472. /* Add buffer BUF to the list of free buffers. */
  473.  
  474. void
  475. free_buffer (buf)
  476.      struct buffer_record *buf;
  477. {
  478.   buf->next = free_list;
  479.   free_list = buf;
  480. }
  481.  
  482. /* Append buffer BUF to the linked list of buffers that contain
  483.    some data yet to be processed. */
  484.  
  485. void
  486. save_buffer (buf)
  487.      struct buffer_record *buf;
  488. {
  489.   struct buffer_record *p;
  490.  
  491.   buf->next = NULL;
  492.   buf->curr_line = buf->line_start;
  493.  
  494.   if (head == NULL)
  495.     head = buf;
  496.   else
  497.     {
  498.       for (p = head; p->next; p = p->next)
  499.     /* Do nothing. */ ;
  500.       p->next = buf;
  501.     }
  502. }
  503.  
  504. /* Fill a buffer of input.
  505.  
  506.    Set the initial size of the buffer to a default.
  507.    Fill the buffer (from the hold area and input stream)
  508.    and find the individual lines.
  509.    If no lines are found (the buffer is too small to hold the next line),
  510.    release the current buffer (whose contents would have been put in the
  511.    hold area) and repeat the process with another large buffer until at least
  512.    one entire line has been read.
  513.  
  514.    Return TRUE if a new buffer was obtained, otherwise false
  515.    (in which case end-of-file must have been encountered). */
  516.  
  517. boolean
  518. load_buffer ()
  519. {
  520.   struct buffer_record *b;
  521.   unsigned bytes_wanted = START_SIZE; /* Minimum buffer size. */
  522.   unsigned bytes_avail;        /* Size of new buffer created. */
  523.   unsigned lines_found;        /* Number of lines in this new buffer. */
  524.   char *p;            /* Place to load into buffer. */
  525.  
  526.   if (have_read_eof)
  527.     return FALSE;
  528.  
  529.   /* We must make the buffer at least as large as the amount of data
  530.      in the partial line left over from the last call. */
  531.   if (bytes_wanted < hold_count)
  532.     bytes_wanted = hold_count;
  533.  
  534.   do
  535.     {
  536.       b = get_new_buffer (bytes_wanted);
  537.       bytes_avail = b->bytes_alloc; /* Size of buffer returned. */
  538.       p = b->buffer;
  539.  
  540.       /* First check the `holding' area for a partial line. */
  541.       if (hold_count)
  542.     {
  543.       if (p != hold_area)
  544.         bcopy (hold_area, p, hold_count);
  545.       p += hold_count;
  546.       b->bytes_used += hold_count;
  547.       bytes_avail -= hold_count;
  548.       hold_count = 0;
  549.     }
  550.  
  551.       b->bytes_used += (unsigned) read_input (p, bytes_avail);
  552.  
  553.       lines_found = record_line_starts (b);
  554.       bytes_wanted = b->bytes_alloc + INCR_SIZE;
  555.       if (!lines_found)
  556.     free_buffer (b);
  557.     }
  558.   while (!lines_found && !have_read_eof);
  559.  
  560.   if (lines_found)
  561.     save_buffer (b);
  562.  
  563.   return lines_found != 0;
  564. }
  565.  
  566. /* Return the line number of the first line that has not yet been retrieved. */
  567.  
  568. unsigned
  569. get_first_line_in_buffer ()
  570. {
  571.   if (head == NULL && !load_buffer ())
  572.     error (1, errno, "input disappeared");
  573.  
  574.   return head->first_available;
  575. }
  576.  
  577. /* Return a pointer to the logical first line in the buffer and make the 
  578.    next line the logical first line.
  579.    Return NULL if there is no more input. */
  580.  
  581. struct cstring *
  582. remove_line ()
  583. {
  584.   struct cstring *line;        /* Return value. */
  585.   unsigned line_got;        /* Number of the line retrieved. */
  586.   struct line *l;        /* For convenience. */
  587.  
  588.   if (head == NULL && !load_buffer ())
  589.     return NULL;
  590.  
  591.   if (current_line < head->first_available)
  592.     current_line = head->first_available;
  593.  
  594.   line_got = head->first_available++;
  595.  
  596.   l = head->curr_line;
  597.  
  598.   line = &l->starts[l->retrieve_index];
  599.  
  600.   /* Advance index to next line. */
  601.   if (++l->retrieve_index == l->used)
  602.     {
  603.       /* Go on to the next line record. */
  604.       head->curr_line = l->next;
  605.       if (head->curr_line == NULL || head->curr_line->used == 0)
  606.     {
  607.       /* Go on to the next data block. */
  608.       struct buffer_record *b = head;
  609.       head = head->next;
  610.       free_buffer (b);
  611.     }
  612.     }
  613.  
  614.   return line;
  615. }
  616.  
  617. /* Search the buffers for line LINENUM, reading more input if necessary.
  618.    Return a pointer to the line, or NULL if it is not found in the file. */
  619.  
  620. struct cstring *
  621. find_line (linenum)
  622.      unsigned linenum;
  623. {
  624.   struct buffer_record *b;
  625.  
  626.   if (head == NULL && !load_buffer ())
  627.     return NULL;
  628.  
  629.   if (linenum < head->start_line)
  630.     return NULL;
  631.  
  632.   for (b = head;;)
  633.     {
  634.       if (linenum < b->start_line + b->num_lines)
  635.     {
  636.       /* The line is in this buffer. */
  637.       struct line *l;
  638.       unsigned offset;    /* How far into the buffer the line is. */
  639.  
  640.       l = b->line_start;
  641.       offset = linenum - b->start_line;
  642.       /* Find the control record. */
  643.       while (offset >= CTRL_SIZE)
  644.         {
  645.           l = l->next;
  646.           offset -= CTRL_SIZE;
  647.         }
  648.       return &l->starts[offset];
  649.     }
  650.       if (b->next == NULL && !load_buffer ())
  651.     return NULL;
  652.       b = b->next;        /* Try the next data block. */
  653.     }
  654. }
  655.  
  656. /* Return TRUE if at least one more line is available for input. */
  657.  
  658. boolean
  659. no_more_lines ()
  660. {
  661.   return (find_line (current_line + 1) == NULL) ? TRUE : FALSE;
  662. }
  663.  
  664. /* Set the name of the input file to NAME and open it. */
  665.  
  666. void
  667. set_input_file (name)
  668.      char *name;
  669. {
  670.   if (!strcmp (name, "-"))
  671.     input_desc = 0;
  672.   else
  673.     {
  674.       input_desc = open (name, O_RDONLY);
  675.       if (input_desc < 0)
  676.     error (1, errno, "%s", name);
  677.     }
  678. }
  679.  
  680. /* Write all lines from the beginning of the buffer up to, but
  681.    not including, line LAST_LINE, to the current output file.
  682.    If IGNORE is TRUE, do not output lines selected here.
  683.    ARGNUM is the index in ARGV of the current pattern. */
  684.  
  685. void
  686. write_to_file (last_line, ignore, argnum)
  687.      unsigned last_line;
  688.      boolean ignore;
  689.      int argnum;
  690. {
  691.   struct cstring *line;
  692.   unsigned first_line;        /* First available input line. */
  693.   unsigned lines;        /* Number of lines to output. */
  694.   unsigned i;
  695.  
  696.   first_line = get_first_line_in_buffer ();
  697.  
  698.   if (first_line > last_line)
  699.     {
  700.       error (0, 0, "%s: line number out of range", global_argv[argnum]);
  701.       cleanup ();
  702.     }
  703.  
  704.   lines = last_line - first_line;
  705.  
  706.   for (i = 0; i < lines; i++)
  707.     {
  708.       line = remove_line ();
  709.       if (line == NULL)
  710.     {
  711.       error (0, 0, "%s: line number out of range", global_argv[argnum]);
  712.       cleanup ();
  713.     }
  714.       if (!ignore)
  715.     save_line_to_file (line);
  716.     }
  717. }
  718.  
  719. /* Output any lines left after all regexps have been processed. */
  720.  
  721. void
  722. dump_rest_of_file ()
  723. {
  724.   struct cstring *line;
  725.  
  726.   while ((line = remove_line ()) != NULL)
  727.     save_line_to_file (line);
  728. }
  729.  
  730. /* Handle an attempt to read beyond EOF under the control of record P,
  731.    on iteration REPETITION if nonzero. */
  732.  
  733. void
  734. handle_line_error (p, repetition)
  735.      struct control *p;
  736.      int repetition;
  737. {
  738.   fprintf (stderr, "%s: `%d': line number out of range",
  739.        program_name, p->lines_required);
  740.   if (repetition)
  741.     fprintf (stderr, " on repetition %d\n", repetition);
  742.   else
  743.     fprintf (stderr, "\n");
  744.  
  745.   cleanup ();
  746. }
  747.  
  748. /* Determine the line number that marks the end of this file,
  749.    then get those lines and save them to the output file.
  750.    P is the control record.
  751.    REPETITION is the repetition number. */
  752.  
  753. void
  754. process_line_count (p, repetition)
  755.      struct control *p;
  756.      int repetition;
  757. {
  758.   unsigned linenum;
  759.   unsigned last_line_to_save = p->lines_required * (repetition + 1);
  760.   struct cstring *line;
  761.  
  762.   create_output_file ();
  763.  
  764.   linenum = get_first_line_in_buffer ();
  765.  
  766.   /* Check for requesting a line that has already been written out.
  767.      If this ever happens, it's due to a bug in csplit. */
  768.   if (linenum >= last_line_to_save)
  769.     handle_line_error (p, repetition);
  770.  
  771.   while (linenum++ < last_line_to_save)
  772.     {
  773.       line = remove_line ();
  774.       if (line == NULL)
  775.     handle_line_error (p, repetition);
  776.       save_line_to_file (line);
  777.     }
  778.  
  779.   close_output_file ();
  780.  
  781.   /* Ensure that the line number specified is not 1 greater than
  782.      the number of lines in the file. */
  783.   if (no_more_lines ())
  784.     handle_line_error (p, repetition);
  785. }
  786.  
  787. void
  788. regexp_error (p, repetition, ignore)
  789.      struct control *p;
  790.      int repetition;
  791.      boolean ignore;
  792. {
  793.   fprintf (stderr, "%s: `%s': match not found",
  794.        program_name, global_argv[p->argnum]);
  795.  
  796.   if (repetition)
  797.     fprintf (stderr, " on repetition %d\n", repetition);
  798.   else
  799.     fprintf (stderr, "\n");
  800.  
  801.   if (!ignore)
  802.     {
  803.       dump_rest_of_file ();
  804.       close_output_file ();
  805.     }
  806.   cleanup ();
  807. }
  808.  
  809. /* Read the input until a line matches the regexp in P, outputting
  810.    it unless P->IGNORE is TRUE.
  811.    REPETITION is this repeat-count; 0 means the first time. */
  812.  
  813. void
  814. process_regexp (p, repetition)
  815.      struct control *p;
  816.      int repetition;
  817. {
  818.   struct cstring *line;        /* From input file. */
  819.   register unsigned line_len;    /* To make "$" in regexps work. */
  820.   unsigned break_line;        /* First line number of next file. */
  821.   boolean ignore = p->ignore;    /* If TRUE, skip this section. */
  822.   int ret;
  823.  
  824.   if (!ignore)
  825.     create_output_file ();
  826.  
  827.   /* If there is no offset for the regular expression, or
  828.      it is positive, then it is not necessary to buffer the lines. */
  829.  
  830.   if (p->offset >= 0)
  831.     {
  832.       for (;;)
  833.     {
  834.       line = find_line (++current_line);
  835.       if (line == NULL)
  836.         regexp_error (p, repetition, ignore);
  837.       line_len = line->len;
  838.       if (line->str[line_len - 1] == '\n')
  839.         line_len--;
  840.       ret = re_search (&p->re_compiled, line->str, line_len,
  841.                0, line_len, (struct re_registers *) 0);
  842.       if (ret == -2)
  843.         {
  844.           error (0, 0, "error in regular expression search");
  845.           cleanup ();
  846.         }
  847.       if (ret == -1)
  848.         {
  849.           line = remove_line ();
  850.           if (!ignore)
  851.         save_line_to_file (line);
  852.         }
  853.       else
  854.         break;
  855.     }
  856.     }
  857.   else
  858.     {
  859.       /* Buffer the lines. */
  860.       for (;;)
  861.     {
  862.       line = find_line (++current_line);
  863.       if (line == NULL)
  864.         regexp_error (p, repetition, ignore);
  865.       line_len = line->len;
  866.       if (line->str[line_len - 1] == '\n')
  867.         line_len--;
  868.       ret = re_search (&p->re_compiled, line->str, line_len,
  869.                0, line_len, (struct re_registers *) 0);
  870.       if (ret == -2)
  871.         {
  872.           error (0, 0, "error in regular expression search");
  873.           cleanup ();
  874.         }
  875.       if (ret >= 0)
  876.         break;
  877.     }
  878.     }
  879.  
  880.   /* Account for any offset from this regexp. */
  881.   break_line = current_line + p->offset;
  882.  
  883.   write_to_file (break_line, ignore, p->argnum);
  884.  
  885.   if (!ignore)
  886.     close_output_file ();
  887.  
  888.   current_line = break_line;
  889. }
  890.  
  891. /* Split the input file according to the control records we have built. */
  892.  
  893. void
  894. split_file ()
  895. {
  896.   register int i, j;
  897.  
  898.   for (i = 0; i < control_used; i++)
  899.     {
  900.       if (controls[i].regexpr)
  901.     {
  902.       for (j = 0; j <= controls[i].repeat; j++)
  903.         process_regexp (&controls[i], j);
  904.     }
  905.       else
  906.     {
  907.       for (j = 0; j <= controls[i].repeat; j++)
  908.         process_line_count (&controls[i], j);
  909.     }
  910.     }
  911.  
  912.   create_output_file ();
  913.   dump_rest_of_file ();
  914.   close_output_file ();
  915. }
  916.  
  917. /* Return the name of output file number NUM. */
  918.  
  919. char *
  920. make_filename (num)
  921.      int num;
  922. {
  923.   sprintf (filename_space, "%s%0*d", prefix, digits, num);
  924.   return filename_space;
  925. }
  926.  
  927. /* Create the next output file. */
  928.  
  929. void
  930. create_output_file ()
  931. {
  932.   char *name;
  933.  
  934.   name = make_filename (files_created);
  935.   output_stream = fopen (name, "w");
  936.   if (output_stream == NULL)
  937.     {
  938.       error (0, errno, "%s", name);
  939.       cleanup ();
  940.     }
  941.   files_created++;
  942.   bytes_written = 0;
  943. }
  944.  
  945. /* Delete all the files we have created. */
  946.  
  947. void
  948. delete_all_files ()
  949. {
  950.   int i;
  951.   char *name;
  952.  
  953.   for (i = 0; i < files_created; i++)
  954.     {
  955.       name = make_filename (i);
  956.       if (unlink (name))
  957.     error (0, errno, "%s", name);
  958.     }
  959. }
  960.  
  961. /* Close the current output file and print the count
  962.    of characters in this file. */
  963.  
  964. void
  965. close_output_file ()
  966. {
  967.   if (output_stream)
  968.     {
  969.       if (fclose (output_stream) == EOF)
  970.     {
  971.       error (0, errno, "write error");
  972.       cleanup ();
  973.     }
  974.       if (!suppress_count)
  975.     fprintf (stdout, "%d\n", bytes_written);
  976.       output_stream = NULL;
  977.     }
  978. }
  979.  
  980. /* Optionally remove files created so far; then exit.
  981.    Called when an error detected. */
  982.  
  983. void
  984. cleanup ()
  985. {
  986.   if (output_stream)
  987.     close_output_file ();
  988.  
  989.   if (remove_files)
  990.     delete_all_files ();
  991.  
  992.   exit (1);
  993. }
  994.  
  995. /* Save line LINE to the output file and
  996.    increment the character count for the current file. */
  997.  
  998. void
  999. save_line_to_file (line)
  1000.      struct cstring *line;
  1001. {
  1002.   fwrite (line->str, sizeof (char), line->len, output_stream);
  1003.   bytes_written += line->len;
  1004. }
  1005.  
  1006. /* Return a new, initialized control record. */
  1007.  
  1008. struct control *
  1009. new_control_record ()
  1010. {
  1011.   static unsigned control_allocated = 0; /* Total space allocated. */
  1012.   register struct control *p;
  1013.  
  1014.   if (control_allocated == 0)
  1015.     {
  1016.       control_allocated = ALLOC_SIZE;
  1017.       controls = (struct control *)
  1018.     xmalloc (sizeof (struct control) * control_allocated);
  1019.     }
  1020.   else if (control_used == control_allocated)
  1021.     {
  1022.       control_allocated += ALLOC_SIZE;
  1023.       controls = (struct control *)
  1024.     xrealloc (controls, sizeof (struct control) * control_allocated);
  1025.     }
  1026.   p = &controls[control_used++];
  1027.   p->regexpr = NULL;
  1028.   p->repeat = 0;
  1029.   p->lines_required = 0;
  1030.   p->offset = 0;
  1031.   return p;
  1032. }
  1033.  
  1034. /* Convert string NUM to an integer and put the value in *RESULT.
  1035.    Return a TRUE if the string consists entirely of digits,
  1036.    FALSE if not. */
  1037.  
  1038. boolean
  1039. string_to_number (result, num)
  1040.      int *result;
  1041.      char *num;
  1042. {
  1043.   register char ch;
  1044.   register int val = 0;
  1045.  
  1046.   if (*num == '\0')
  1047.     return FALSE;
  1048.  
  1049.   while (ch = *num++)
  1050.     {
  1051.       if (!isdigit (ch))
  1052.     return FALSE;
  1053.       val = val * 10 + ch - '0';
  1054.     }
  1055.  
  1056.   *result = val;
  1057.   return TRUE;
  1058. }
  1059.  
  1060. /* Check if there is a numeric offset after a regular expression.
  1061.    STR is the entire command line argument.
  1062.    ARGNUM is the index in ARGV of STR.
  1063.    P is the control record for this regular expression.
  1064.    NUM is the numeric part of STR. */
  1065.  
  1066. void
  1067. check_for_offset (argnum, p, str, num)
  1068.      int argnum;
  1069.      struct control *p;
  1070.      char *str;
  1071.      char *num;
  1072. {
  1073.   if (*num != '-' && *num != '+')
  1074.     error (1, 0, "%s: `+' or `-' expected after delimeter", str);
  1075.  
  1076.   if (!string_to_number (&p->offset, num + 1))
  1077.     error (1, 0, "%s: integer expected after `%c'", str, *num);
  1078.  
  1079.   if (*num == '-')
  1080.     p->offset = -p->offset;
  1081. }
  1082.  
  1083. /* Given that the first character of command line arg STR is '{',
  1084.    make sure that the rest of the string is a valid repeat count
  1085.    and store its value in P.
  1086.    ARGNUM is the ARGV index of STR. */
  1087.  
  1088. void
  1089. parse_repeat_count (argnum, p, str)
  1090.      int argnum;
  1091.      struct control *p;
  1092.      char *str;
  1093. {
  1094.   char *end;
  1095.  
  1096.   end = str + strlen (str) - 1;
  1097.   if (*end != '}')
  1098.     error (1, 0, "%s: `}' is required in repeat count", str);
  1099.   *end = '\0';
  1100.  
  1101.   if (!string_to_number (&p->repeat, str +  1))
  1102.     error (1, 0, "%s}: integer required between `{' and `}'",
  1103.        global_argv[argnum]);
  1104.  
  1105.   *end = '}';
  1106. }
  1107.  
  1108. /* Extract the regular expression from STR and check for a numeric offset.
  1109.    STR should start with the regexp delimiter character.
  1110.    Return a new control record for the regular expression.
  1111.    ARGNUM is the ARGV index of STR.
  1112.    Unless IGNORE is TRUE, mark these lines for output. */
  1113.  
  1114. struct control *
  1115. extract_regexp (argnum, ignore, str)
  1116.      int argnum;
  1117.      boolean ignore;
  1118.      char *str;
  1119. {
  1120.   int len;            /* Number of chars in this regexp. */
  1121.   char delim = *str;
  1122.   char *closing_delim;
  1123.   struct control *p;
  1124.   char *err;
  1125.  
  1126.   closing_delim = rindex (str + 1, delim);
  1127.   if (closing_delim == NULL)
  1128.     error (1, 0, "%s: closing delimeter `%c' missing", str, delim);
  1129.  
  1130.   len = closing_delim - str - 1;
  1131.   p = new_control_record ();
  1132.   p->argnum = argnum;
  1133.   p->ignore = ignore;
  1134.  
  1135.   p->regexpr = (char *) xmalloc ((unsigned) (len + 1));
  1136.   strncpy (p->regexpr, str + 1, len);
  1137.   p->re_compiled.allocated = len * 2;
  1138.   p->re_compiled.buffer = (unsigned char *) xmalloc (p->re_compiled.allocated);
  1139.   p->re_compiled.fastmap = xmalloc (256);
  1140.   p->re_compiled.translate = 0;
  1141.   err = re_compile_pattern (p->regexpr, len, &p->re_compiled);
  1142.   if (err)
  1143.     {
  1144.       error (0, 0, "%s: invalid regular expression: %s", str, err);
  1145.       cleanup ();
  1146.     }
  1147.  
  1148.   if (closing_delim[1])
  1149.     check_for_offset (argnum, p, str, closing_delim + 1);
  1150.  
  1151.   return p;
  1152. }
  1153.  
  1154. /* Extract the break patterns from args START through ARGC - 1 of ARGV.
  1155.    After each pattern, check if the next argument is a repeat count. */
  1156.  
  1157. void
  1158. parse_patterns (argc, start, argv)
  1159.      int argc;
  1160.      int start;
  1161.      char **argv;
  1162. {
  1163.   int i;            /* Index into ARGV. */
  1164.   struct control *p;        /* New control record created. */
  1165.  
  1166.   for (i = start; i < argc; i++)
  1167.     {
  1168.       if (*argv[i] == '/' || *argv[i] == '%')
  1169.     {
  1170.       p = extract_regexp (i, *argv[i] == '%', argv[i]);
  1171.     }
  1172.       else
  1173.     {
  1174.       p = new_control_record ();
  1175.       p->argnum = i;
  1176.       if (!string_to_number (&p->lines_required, argv[i]))
  1177.         error (1, 0, "%s: invalid pattern", argv[i]);
  1178.     }
  1179.  
  1180.       if (i + 1 < argc && *argv[i + 1] == '{')
  1181.     {
  1182.       /* We have a repeat count. */
  1183.       i++;
  1184.       parse_repeat_count (i, p, argv[i]);
  1185.     }
  1186.     }
  1187. }
  1188.  
  1189. void
  1190. interrupt_handler ()
  1191. {
  1192.   error (0, 0, "interrupted");
  1193.   cleanup ();
  1194. }
  1195.  
  1196. struct option longopts[] =
  1197. {
  1198.   {"digits", 1, NULL, 'n'},
  1199.   {"quiet", 0, NULL, 's'},
  1200.   {"silent", 0, NULL, 's'},
  1201.   {"keep-files", 0, NULL, 'k'},
  1202.   {"prefix", 1, NULL, 'f'},
  1203.   {NULL, 0, NULL, 0}
  1204. };
  1205.  
  1206. void
  1207. main (argc, argv)
  1208.      int argc;
  1209.      char **argv;
  1210. {
  1211.   int optc;
  1212. #ifdef _POSIX_VERSION
  1213.   struct sigaction oldact, newact;
  1214. #endif                /* _POSIX_VERSION */
  1215.  
  1216.   program_name = argv[0];
  1217.   global_argv = argv;
  1218.   controls = NULL;
  1219.   control_used = 0;
  1220.   suppress_count = FALSE;
  1221.   remove_files = TRUE;
  1222.   prefix = DEFAULT_PREFIX;
  1223.  
  1224. #ifdef _POSIX_VERSION
  1225.   newact.sa_handler = interrupt_handler;
  1226.   sigemptyset (&newact.sa_mask);
  1227.   newact.sa_flags = 0;
  1228.  
  1229.   sigaction (SIGHUP, NULL, &oldact);
  1230.   if (oldact.sa_handler != SIG_IGN)
  1231.     sigaction (SIGHUP, &newact, NULL);
  1232.  
  1233.   sigaction (SIGINT, NULL, &oldact);
  1234.   if (oldact.sa_handler != SIG_IGN)
  1235.     sigaction (SIGINT, &newact, NULL);
  1236.  
  1237.   sigaction (SIGQUIT, NULL, &oldact);
  1238.   if (oldact.sa_handler != SIG_IGN)
  1239.     sigaction (SIGQUIT, &newact, NULL);
  1240.  
  1241.   sigaction (SIGTERM, NULL, &oldact);
  1242.   if (oldact.sa_handler != SIG_IGN)
  1243.     sigaction (SIGTERM, &newact, NULL);
  1244. #else                /* !_POSIX_VERSION */
  1245.   if (signal (SIGHUP, SIG_IGN) != SIG_IGN)
  1246.     signal (SIGHUP, interrupt_handler);
  1247.   if (signal (SIGINT, SIG_IGN) != SIG_IGN)
  1248.     signal (SIGINT, interrupt_handler);
  1249.   if (signal (SIGQUIT, SIG_IGN) != SIG_IGN)
  1250.     signal (SIGQUIT, interrupt_handler);
  1251.   if (signal (SIGTERM, SIG_IGN) != SIG_IGN)
  1252.     signal (SIGTERM, interrupt_handler);
  1253. #endif
  1254.  
  1255.   while ((optc = getopt_long (argc, argv, "f:kn:s", longopts, (int *) 0))
  1256.      != EOF)
  1257.     switch (optc)
  1258.       {
  1259.       case 'f':
  1260.     prefix = optarg;
  1261.     break;
  1262.  
  1263.       case 'k':
  1264.     remove_files = FALSE;
  1265.     break;
  1266.  
  1267.       case 'n':
  1268.     if (!string_to_number (&digits, optarg))
  1269.       error (1, 0, "%s: invalid number", optarg);
  1270.     break;
  1271.  
  1272.       case 's':
  1273.     suppress_count = TRUE;
  1274.     break;
  1275.  
  1276.       default:
  1277.     usage ();
  1278.       }
  1279.  
  1280.   if (optind >= argc - 1)
  1281.     usage ();
  1282.  
  1283.   filename_space = (char *) xmalloc (strlen (prefix) + digits + 2);
  1284.  
  1285.   set_input_file (argv[optind++]);
  1286.  
  1287.   parse_patterns (argc, optind, argv);
  1288.  
  1289.   split_file ();
  1290.  
  1291.   if (close (input_desc) < 0)
  1292.     {
  1293.       error (0, errno, "read error");
  1294.       cleanup ();
  1295.     }
  1296.  
  1297.   exit (0);
  1298. }
  1299.  
  1300. void
  1301. usage ()
  1302. {
  1303.   fprintf (stderr, "\
  1304. Usage: %s [-sk] [-f prefix] [-n digits] [--prefix=prefix]\n\
  1305.        [--digits=digits] [--quiet] [--silent] [--keep-files] file pattern...\n",
  1306.        program_name);
  1307.   exit (1);
  1308. }
  1309.